using OhioState.Graphics;
using Tao.OpenGl;

namespace OhioState.Graphics.OpenGL
{

	/// <summary>
	/// This contains static methods which doe services for Blending by calling Tao.OpenGl
	///  so that we can get away from remoting OpenGL context
	/// </summary>
	public class GLBlend
	{
		#region public method
        /// <summary>
        /// Turn on blending
        /// </summary>
        public static void ApplyBlending()
        {
            Gl.glEnable(Gl.GL_BLEND);
        }

        /// <summary>
        /// Turn off blending
        /// </summary>
        public static void RemoveBlending()
        {
            Gl.glDisable(Gl.GL_BLEND);
        }

        /// <summary>
        /// Set-up the blend function to correspond to the indicated
        /// blending mode.
        /// </summary>
        /// <param name="blending">The desired <typeparamref name="BlendMode"/>.</param>
        public static void SetBlendFunctionType(BlendMode blending)
        {
            switch (blending)
            {
                case BlendMode.ADD:
                    SetBlendingFunctionAdd();
                    break;
                case BlendMode.MAX:
                    SetBlendingFunctionMax();
                    break;
                case BlendMode.MIN:
                    SetBlendingFunctionMin();
                    break;
                case BlendMode.OVER:
                    SetBlendingFunctionOver();
                    break;
                case BlendMode.REPLACE:
                    SetBlendingFunctionReplace();
                    break;
                case BlendMode.TRANSPARENT:
                    SetBlendingFunctionTransparent();
                    break;
            }
        }
		#endregion

		#region private Methods
        private static void SetBlendingFunctionAdd()
        {
            //set blending function to add the fragement (non-associative) to the framebuffer.
            Gl.glBlendFunc(Gl.GL_ONE, Gl.GL_ONE);
            Gl.glBlendFuncSeparate(Gl.GL_ONE, Gl.GL_ONE, Gl.GL_ONE, Gl.GL_ONE);
            //set blending equation to add components (default behavior)
            Gl.glBlendEquation(Gl.GL_FUNC_ADD);
        }

        private static void SetBlendingFunctionMax()
        {
            //set blending function to not affect source and destination fragments
            Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE);
            //set blending equation to take maximum color
            Gl.glBlendEquation(Gl.GL_MAX);
        }

        private static void SetBlendingFunctionMin()
        {
            //set blending function (will not alter fragments color values)
            Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE);
            //set blending equation for selecting minumum color
            Gl.glBlendEquation(Gl.GL_MIN);
        }

        private static void SetBlendingFunctionOver()
        {
            //set blending function for over operator
            Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
            Gl.glBlendFuncSeparate(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA, Gl.GL_ONE_MINUS_DST_ALPHA, Gl.GL_ONE);
            //set blending equation to add components (default behavior)
            Gl.glBlendEquation(Gl.GL_FUNC_ADD);
        }

        private static void SetBlendingFunctionReplace()
        {
            //set the blending function
            Gl.glBlendFunc(Gl.GL_ONE, Gl.GL_ZERO);
            //set the blending equation (default should be GL_FUNC_ADD, force it)
            Gl.glBlendEquation(Gl.GL_FUNC_ADD);
        }

        private static void SetBlendingFunctionTransparent()
        {
            //set blending function to treat fragments as transparent
            Gl.glBlendFunc(Gl.GL_ONE, Gl.GL_ONE_MINUS_SRC_ALPHA);
            Gl.glBlendFuncSeparate(Gl.GL_ONE, Gl.GL_ONE_MINUS_SRC_ALPHA, Gl.GL_ONE_MINUS_DST_ALPHA, Gl.GL_ONE);

            //set equation to addative blending (default behavior)
            Gl.glBlendEquation(Gl.GL_FUNC_ADD);
        }
		#endregion
	}
}
